(load "promise.ss")
(define-syntax make-stream
  (syntax-rules ()
    [(_ x y) (cons x (delay y))]))

(define TheEmptyStream '())

(define (head s)
  (car s))

(define (tail s)
  (force (cdr s)))

(define (empty-stream? s)
  (eq? (head s) TheEmptyStream))

(define (map fn s)
  (if (not (empty-stream? s))
    (make-stream
       (fn (head s))
       (map fn (tail s)))))

(define (filter pred? s)
  (if (not (empty-stream? s))
    (if (pred? (head s))
       (make-stream (head s) (filter pred? (tail s)))
       (filter pred? (tail s)))
    TheEmptyStream))

(define (print-stream s)
  (cond [(empty-stream? s) "done"]
        [else 
          (display (head s))
          (print-stream (tail s))]))

;; call-once
(define (memo-proc proc)
  (let ([already-run? nil] [result nil])
    (lambda ()
      (if (not already-run?)
        (begin
          (set! result (proc))
          (set! already-run? #t)
          result)
        result))))

(define (nth-stream n s)
  (if (= n 0)
    (head s)
    (nth-stream (- n 1) (tail s))))

(define (integer-from n)
  (make-stream
    n
    (integer-from (+ n 1))))

(nth-stream 20 (integer-from 1))
